#include <QDebug>
#include <QTimer>

#include "ConstData.h"
#include "ConstNames.h"
#include "DeviceSpikeHelper.h"
#include "ModbusManager.h"
#include "sql/database.h"
/*

1.质控仪：0304H设置0000 RS232通讯控制; 006FH设置成 0x0001加标回收; 0064H设置成
0x01选择动态加标;0099H设置成 0x01启动流程，开始运行

2.质控仪：轮询读取 0303H(0、未准备完成 1 、准备完成) ，若准备完成则启动分析仪

3.质控仪：向0302H写入0x0001告诉质控仪开始分析；分析仪：向199写入0x0001开始分析

4.分析仪：轮询结果，等待0001H浓度寄存器值跳变获取浓度值（Float ABCD）

5.质控仪：向 0300H 0301H 写入浓度值（Float ABCD）；向 0302H 写入 0x0000 告诉质控仪分析完成；质控
仪开始进行加标液操作

6.质控仪：轮询读取 0303H(0、未准备完成 1 、准备完成) ，若准备完成则启动分析仪

7.质控仪：向0302H写入0x0001告诉质控仪开始分析；分析仪：向199写入0x0001开始分析

8.分析仪：轮询结果，等待0001H浓度寄存器值跳变获取浓度值（Float ABCD）

9.质控仪：向 0300H 0301H 写入浓度值（Float ABCD）；向 0302H 写入 0x0000 告诉质控仪分析完成；

10.质控仪：计算加标回收率 X；工控机可读取 X 值（0305H 0306H）

*/
// 加标回收专用的Modbus寄存器定义
#define REG_SPIKE_MODE 0x006F             // 加标回收模式
#define REG_DYNAMIC_SPIKE 0x0064          // 动态加标
#define REG_START_PROCESS 0x0099          // 启动流程
#define REG_COMMUNICATION_CONTROL 0x0304  // 通讯控制
#define REG_READY_STATUS 0x0303           // 准备状态
#define REG_ANALYSIS_CONTROL 0x0302       // 分析控制
#define REG_CONCENTRATION_LOW 0x0300      // 浓度值低位
#define REG_RECOVERY_LOW 0x0305           // 回收率低位

void DeviceSpikeHelper::loadSpikeRecoveryConfig()
{
    // 使用SPIKE_TO_NORMAL_MAP获取对应的测量设备名称
    if (SPIKE_TO_NORMAL_MAP.contains(m_deviceName)) {
        m_measureDeviceName = SPIKE_TO_NORMAL_MAP[m_deviceName];
    }
}

ModbusHelper* DeviceSpikeHelper::getMeasureModbus()
{
    if (!m_modbusManager || m_measureDeviceName.isEmpty()) {
        return nullptr;
    }
    return m_modbusManager->getModbusHelper(m_measureDeviceName);
}

void DeviceSpikeHelper::startSpikeRecovery()
{
    if (m_isSpikeRecoveryMode) {
        return;
    }

    if (m_measureDeviceName.isEmpty()) {
        handleSpikeRecoveryError("未配置关联的测量设备");
        return;
    }

    ModbusHelper* spikeModbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    ModbusHelper* measureModbus = getMeasureModbus();

    if (!spikeModbus || !measureModbus) {
        handleSpikeRecoveryError("设备Modbus连接失败");
        return;
    }

    m_isSpikeRecoveryMode = true;
    m_currentSpikeRecoveryStep = SpikeRecoveryStep::INIT_SETTINGS;

    // 重置轮询标志
    m_isFirstRead1 = true;
    m_isFirstRead2 = true;

    executeSpikeRecoveryStep();
}

void DeviceSpikeHelper::executeSpikeRecoveryStep()
{
    switch (m_currentSpikeRecoveryStep) {
        case SpikeRecoveryStep::INIT_SETTINGS:
            qDebug() << "执行初始化设置";
            m_startTime = QDateTime::currentDateTime();
            step_InitSettings();
            break;
        case SpikeRecoveryStep::ANALYSIS1:
            qDebug() << "等待加标仪操作完成；并执行第一次分析";
            m_stepTimer->stop();
            step_Analysis1();
            m_stepTimer->start(90 * 60 * 1000);  // 1.5小时超时
            break;
        case SpikeRecoveryStep::ANALYSIS2:
            qDebug() << "等待加标仪操作完成；并执行第二次分析";
            m_stepTimer->stop();
            step_Analysis2();
            m_stepTimer->start(90 * 60 * 1000);  // 1.5小时超时
            break;
        case SpikeRecoveryStep::READING_RESULT:
            qDebug() << "读取加标回收率";
            m_stepTimer->stop();
            step_ReadResult();
            break;
        case SpikeRecoveryStep::IDLE:
            // 空闲状态，不执行任何操作
            break;
    }
}

void DeviceSpikeHelper::step_InitSettings()
{
    ModbusHelper* spikeModbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!spikeModbus) {
        handleSpikeRecoveryError("Modbus连接无效");
        return;
    }

    // 初始化设置：通讯控制、加标回收模式、动态加标、启动流程
    spikeModbus->asyncWrite(REG_COMMUNICATION_CONTROL, QVector<quint16>{0x0000})
        .then([this, spikeModbus]() {
            return spikeModbus->asyncWrite(REG_SPIKE_MODE, QVector<quint16>{0x0001});
        })
        .then([this, spikeModbus]() {
            return spikeModbus->asyncWrite(REG_DYNAMIC_SPIKE, QVector<quint16>{0x0001});
        })
        .then([this, spikeModbus]() {
            return spikeModbus->asyncWrite(REG_START_PROCESS, QVector<quint16>{0x0001});
        })
        .then([this]() {
            m_currentSpikeRecoveryStep = SpikeRecoveryStep::ANALYSIS1;
            QTimer::singleShot(3000, this, &DeviceSpikeHelper::executeSpikeRecoveryStep);
        })
        .fail([this](const QString& error) {
            handleSpikeRecoveryError(QString("初始化设置失败: %1").arg(error));
        });
}

void DeviceSpikeHelper::step_Analysis1()
{
    executeAnalysisStep(1, &DeviceSpikeHelper::step_Analysis1, "第一次分析失败");
}

void DeviceSpikeHelper::step_Analysis2()
{
    executeAnalysisStep(2, &DeviceSpikeHelper::step_Analysis2, "第二次分析失败");
}

void DeviceSpikeHelper::executeAnalysisStep(int step, void (DeviceSpikeHelper::*retryFunc)(),
                                            const QString& errorPrefix)
{
    ModbusHelper* spikeModbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    ModbusHelper* measureModbus = getMeasureModbus();

    if (!spikeModbus || !measureModbus) {
        handleSpikeRecoveryError("Modbus连接无效");
        return;
    }

    // 轮询读取准备状态
    spikeModbus->asyncRead(REG_READY_STATUS, 1)
        .then([this, spikeModbus, measureModbus, step, retryFunc](const QVector<quint16>& result) {
            if (!result.isEmpty() && result[0] == 1) {
                // 准备完成，启动分析
                return spikeModbus->asyncWrite(REG_ANALYSIS_CONTROL, QVector<quint16>({0x0001}))
                    .then([this, measureModbus]() {
                        return measureModbus->asyncWrite(199, QVector<quint16>({0x0001}));
                    })
                    .then([this, step]() { pollAnalysis(step); });
            } else {
                // 准备未完成，继续轮询
                QTimer::singleShot(1000, this, retryFunc);
                return QtPromise::resolve();
            }
        })
        .fail([this, errorPrefix](const QString& error) {
            handleSpikeRecoveryError(QString("%1: %2").arg(errorPrefix).arg(error));
        });
}

void DeviceSpikeHelper::step_ReadResult()
{
    ModbusHelper* spikeModbus = ModbusManager::instance()->getModbusHelper(m_deviceName);

    if (!spikeModbus) {
        handleSpikeRecoveryError("加标仪器Modbus连接无效");
        return;
    }

    // 读取加标回收率
    spikeModbus->asyncReadFloat(REG_RECOVERY_LOW, 1, MB_ABCD)
        .then([this](const QVector<float>& values) {
            if (!values.isEmpty()) {
                m_recoveryRate = values[0];
                m_deviceData.analyze_lastResult = m_recoveryRate;
                completeSpikeRecovery();
            } else {
                handleSpikeRecoveryError("读取回收率数据为空");
            }
        })
        .fail([this](const QString& error) {
            handleSpikeRecoveryError(QString("读取加标回收率失败: %1").arg(error));
        });
}

void DeviceSpikeHelper::pollAnalysis(int step)
{
    ModbusHelper* measureModbus = getMeasureModbus();
    if (!measureModbus) {
        handleSpikeRecoveryError("测量仪器Modbus连接无效");
        return;
    }

    // 轮询浓度寄存器值跳变
    measureModbus->asyncReadFloat(1, 1)
        .then([this, step](const QVector<float>& result) {
            if (!result.isEmpty()) {
                float currentResult = result[0];

                // 根据步骤选择对应的变量
                float& baselineValue = (step == 1) ? m_baselineValue1 : m_baselineValue2;
                bool& isFirstRead = (step == 1) ? m_isFirstRead1 : m_isFirstRead2;
                float& concentration = (step == 1) ? m_concentration1 : m_concentration2;

                if (isFirstRead) {
                    // 第一次读取，存储基准值
                    baselineValue = currentResult;
                    isFirstRead = false;
                    QTimer::singleShot(1000, this, [this, step]() { pollAnalysis(step); });
                } else {
                    // 检测相对于基准值的跳变
                    if (baselineValue != currentResult) {
                        concentration = currentResult;
                        writeConcentrationAndFinish(step);
                    } else {
                        // 结果未跳变，继续轮询
                        QTimer::singleShot(1000, this, [this, step]() { pollAnalysis(step); });
                    }
                }
            } else {
                handleSpikeRecoveryError("读取浓度寄存器数据为空");
            }
        })
        .fail([this](const QString& error) {
            handleSpikeRecoveryError(QString("轮询浓度寄存器失败: %1").arg(error));
        });
}

void DeviceSpikeHelper::writeConcentrationAndFinish(int step)
{
    const float concentration = (step == 1) ? m_concentration1 : m_concentration2;

    ModbusHelper* spikeModbus = ModbusManager::instance()->getModbusHelper(m_deviceName);

    if (!spikeModbus) {
        handleSpikeRecoveryError("加标仪器Modbus连接无效");
        return;
    }

    // 写入浓度值
    QVector<float> floatValues = {concentration};
    QVector<quint16> floatRegs = spikeModbus->floatsToRegisters(floatValues, MB_ABCD);

    spikeModbus->asyncWrite(REG_CONCENTRATION_LOW, floatRegs)
        .then([this, spikeModbus]() {
            // 通知质控仪分析完成
            return spikeModbus->asyncWrite(REG_ANALYSIS_CONTROL, QVector<quint16>({0x0000}));
        })
        .then([this, step]() {
            if (step == 1) {
                m_currentSpikeRecoveryStep = SpikeRecoveryStep::ANALYSIS2;
            } else {
                m_currentSpikeRecoveryStep = SpikeRecoveryStep::READING_RESULT;
            }
            QTimer::singleShot(3000, this, &DeviceSpikeHelper::executeSpikeRecoveryStep);
        })
        .fail([this](const QString& error) {
            handleSpikeRecoveryError(QString("分析完成操作失败: %1").arg(error));
        });
}

void DeviceSpikeHelper::completeSpikeRecovery()
{
    qDebug() << QString("完成 - 原始水样浓度：%1, 加标水样浓度：%2, 回收率: %3")
                    .arg(m_concentration1, 0, 'f', 3)
                    .arg(m_concentration2, 0, 'f', 3)
                    .arg(m_recoveryRate, 0, 'f', 2);

    // 插入加标回收记录到数据库
    bool success = Database::insertSpikeRecoveryRecord(m_deviceName,
                                                       m_concentration1,  // 原始水样浓度
                                                       m_concentration2,  // 加标水样浓度
                                                       m_recoveryRate,    // 加标回收率
                                                       m_startTime);
    m_isSpikeRecoveryMode = false;

    // 重置到空闲状态
    QTimer::singleShot(3000, this,
                       [this]() { m_currentSpikeRecoveryStep = SpikeRecoveryStep::IDLE; });
}

void DeviceSpikeHelper::handleSpikeRecoveryError(const QString& error)
{
    m_stepTimer->stop();

    m_currentSpikeRecoveryStep = SpikeRecoveryStep::IDLE;
    m_isSpikeRecoveryMode = false;

    emit errorOccurred(error);
}

void DeviceSpikeHelper::onStepTimeout() { handleSpikeRecoveryError("步骤执行超时"); }